﻿
#define FMT_HEADER_ONLY
#define FMT_UNICODE 0
#include <fmt/core.h>
#include <fmt/ranges.h>

#include "ATChannel.hpp"

#include "nonstd/scope.hpp"

// clang-format off
static const std::string at_cmds1[] = {
    "ATE0\r\n",
    "ATI\r\n",
};
// clang-format on

int main()
{
    std::unique_ptr<ATChannel> serial;

    auto serial_guard = nonstd::make_scope_exit([&]() {
        serial.reset();
    });

    std::string portname = "COM3";

    std::vector<std::string> vs;

    int result;

    try
    {
        serial = std::make_unique<ATChannel>(portname);
        if (serial->at_handshake() != 1)
        {
            fmt::println("at handshake faild.");
            return -1;
        }
        else
        {
            fmt::println("at handshake success.");
        }
    }
    catch (const std::exception&)
    {
        fmt::println("open serial faild. {}", portname);
        return -1;
    }
    
    do
    {
        std::this_thread::sleep_for(std::chrono::seconds(1));

        //serial->at_transmit(s, vs);
        //serial->at_transmit_single(s, e, r);

        for (std::string _cmd : at_cmds1)
        {
            result = serial->at_transmit(_cmd, vs);
            if (result < 0)
                break;
        }
    } while (0);
}

// #define LIB_SERIAL_PORT
#define SERIAL_LIB

#if defined(SERIAL_LIB)
#include "serialib.h"
#elif defined(LIB_SERIAL_PORT)
#include "libserialport.h"
#else
#error("NO SERIAL")
#endif

void* serial_open(const char* name, int baudrate, char parity, int bits, int stopbits)
{
#if defined(SERIAL_LIB)
    serialib* serial = new serialib();

    if (serial->openDevice(name, baudrate))
        return serial;
    return NULL;
#elif defined(LIB_SERIAL_PORT)
    struct sp_port* port = NULL;

    enum sp_return result;

    result = sp_get_port_by_name(name, &port);
    if (result != SP_OK)
    {
        return NULL;
    }

    result = sp_open(port, SP_MODE_READ_WRITE);
    if (result != SP_OK)
    {
        return NULL;
    }

    sp_set_baudrate(port, baudrate);
    sp_set_bits(port, bits);
    sp_set_stopbits(port, stopbits);
    switch (parity)
    {
    case 'E':
        sp_set_parity(port, sp_parity(SP_PARITY_EVEN));
        break;
    case 'O':
        sp_set_parity(port, sp_parity(SP_PARITY_ODD));
        break;
    case 'N':
        sp_set_parity(port, sp_parity(SP_PARITY_NONE));
        break;
    default:
        throw std::runtime_error("Invalid parity setting");
    }
    sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE);

    return port;
#endif
}

void serial_close(void* fd)
{
#if defined(SERIAL_LIB)
    serialib* serial = (serialib*)fd;
    serial->closeDevice();
#elif defined(LIB_SERIAL_PORT)
    struct sp_port* port = (struct sp_port*)fd;

    sp_close(port);
    sp_free_port(port);
#endif
}

int serial_write(void* fd, const nonstd::span<char>& arr)
{
#if defined(SERIAL_LIB)
    serialib* serial = (serialib*)fd;
    return serial->writeBytes(arr.data(), (unsigned int)arr.size());
#elif defined(LIB_SERIAL_PORT)
    struct sp_port* port = (struct sp_port*)fd;
    return sp_blocking_write(port, arr.data(), arr.size(), 1000);
#endif
}

int serial_read(void* fd, const nonstd::span<char>& arr, unsigned int timeout_ms)
{
#if defined(SERIAL_LIB)
    serialib* serial = (serialib*)fd;
    return serial->readBytes(arr.data(), (unsigned int)arr.size(), 5);
#elif defined(LIB_SERIAL_PORT)
    struct sp_port* port = (struct sp_port*)fd;
    return (int)sp_blocking_read_next(port, arr.data(), arr.size(), timeout_ms);
#endif
}

